package com.example.demo.leetcode.classics150;

import java.util.LinkedList;
import java.util.List;

/**
 * ******************************************************
 *
 * @author liugh9
 * @version 1.0
 * @classname _38生命游戏
 * @description
 * @date 2023/07/20 14:25
 * <p>
 * ******************************************************
 */
public class _38生命游戏 {


    /**
     * 根据 百度百科 ， 生命游戏 ，简称为 生命 ，是英国数学家约翰·何顿·康威在 1970 年发明的细胞自动机。
     * <p>
     * 给定一个包含 m × n 个格子的面板，每一个格子都可以看成是一个细胞。
     * 每个细胞都具有一个初始状态： 1 即为 活细胞 （live），或 0 即为 死细胞 （dead）。
     * 每个细胞与其八个相邻位置（水平，垂直，对角线）的细胞都遵循以下四条生存定律：
     * <p>
     * 如果活细胞周围八个位置的活细胞数少于两个，则该位置活细胞死亡；
     * 如果活细胞周围八个位置有两个或三个活细胞，则该位置活细胞仍然存活；
     * 如果活细胞周围八个位置有超过三个活细胞，则该位置活细胞死亡；
     * 如果死细胞周围正好有三个活细胞，则该位置死细胞复活；
     * 下一个状态是通过将上述规则同时应用于当前状态下的每个细胞所形成的，
     * 其中细胞的出生和死亡是同时发生的。给你 m x n 网格面板 board 的当前状态，返回下一个状态。
     * <p>
     * <p>
     * <p>
     * 示例 1：
     * <p>
     * <p>
     * 输入：board = [[0,1,0],[0,0,1],[1,1,1],[0,0,0]]
     * 输出：[[0,0,0],[1,0,1],[0,1,1],[0,1,0]]
     * 示例 2：
     * <p>
     * <p>
     * 输入：board = [[1,1],[1,0]]
     * 输出：[[1,1],[1,1]]
     * <p>
     * <p>
     * 提示：
     * <p>
     * m == board.length
     * n == board[i].length
     * 1 <= m, n <= 25
     * board[i][j] 为 0 或 1
     *
     * @param board
     */
    public void gameOfLife(int[][] board) {
        int m = board.length;
        int n = board[0].length;
        List<int[]> changes = new LinkedList<>();
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (deathOrResurrection(board, i, j)) {
                    changes.add(new int[]{i, j});
                }
            }
        }

        for (int[] change : changes) {
            board[change[0]][change[1]] = Math.abs(board[change[0]][change[1]] - 1);
        }
    }

    private final int[][] around = new int[][]{
            {-1, -1},
            {-1, 0},
            {-1, 1},
            {0, -1},
            {0, 1},
            {1, -1},
            {1, 0},
            {1, 1},
    };

    private boolean deathOrResurrection(int[][] board, int i, int j) {
        int m = board.length;
        int n = board[0].length;
        int status = board[i][j];
        // 计算四周活细胞数量
        int row, col;
        int count_resurrection = 0;
        for (int[] item : around) {
            row = i + item[0];
            col = j + item[1];
            if (row >= 0 && row < m && col >=0 && col < n) {
                if (board[row][col] == 1) {
                    count_resurrection++;
                }
            }
        }

        if (status == 1) {
            // 存活

            // 1、如果活细胞周围八个位置的活细胞数少于两个，则该位置活细胞死亡；
            // 2、如果活细胞周围八个位置有两个或三个活细胞，则该位置活细胞仍然存活；
            // 3、如果活细胞周围八个位置有超过三个活细胞，则该位置活细胞死亡；

            if (count_resurrection < 2 || count_resurrection > 3) {
                return true;
            }
        } else {
            // 死亡
            // 4、如果死细胞周围正好有三个活细胞，则该位置死细胞复活；
            if (count_resurrection == 3) {
                return true;
            }
        }

        return false;

    }

    public static void main(String[] args) {
        _38生命游戏 s = new _38生命游戏();
        s.gameOfLife(new int[][]{{0,1,0}
                ,{0,0,1}
                ,{1,1,1}
                ,{0,0,0}});
    }


}
